<template>
  <div class="grid" style="gap: 12px">
    <el-form label-position="top" label-width="auto">
      <el-form-item label="本金">
        <el-input-number v-model="state.principal" :min="0" :step="100" />
      </el-form-item>

      <div
        class="row"
        style="display: grid; grid-template-columns: 1fr 1fr; gap: 12px">
        <el-form-item label="利率（%）">
          <el-input-number
            v-model="state.ratePercent"
            :min="0"
            :max="100"
            :step="0.1" />
        </el-form-item>
        <el-form-item label="复利频率">
          <el-select v-model="state.periodsPerYear">
            <el-option label="按年" :value="1" />
            <el-option label="按季度" :value="4" />
            <el-option label="按月" :value="12" />
            <el-option label="按日" :value="365" />
          </el-select>
        </el-form-item>
      </div>

      <div
        class="row"
        style="display: grid; grid-template-columns: 1fr 1fr; gap: 12px">
        <el-form-item label="年限">
          <el-input-number v-model="state.years" :min="0" :step="0.5" />
        </el-form-item>
        <!-- <el-form-item label="每期追加">
          <el-input-number v-model="state.contribution" :min="0" :step="10" />
        </el-form-item> -->
      </div>

      <!-- <el-form-item label="追加时点">
        <el-radio-group v-model="state.timing">
          <el-radio-button label="end">期末</el-radio-button>
          <el-radio-button label="start">期初</el-radio-button>
        </el-radio-group>
      </el-form-item> -->

      <div class="display" style="font-size: 20px; padding: 10px">
        <div>结果：{{ futureValueText }}</div>
        <div class="text-red-500" style="margin-top: 6px">
          利润：{{ profitText }}
        </div>
      </div>
    </el-form>
  </div>
</template>

<script setup lang="ts">
import {
  ElForm,
  ElFormItem,
  ElInputNumber,
  ElOption,
  ElRadioButton,
  ElRadioGroup,
  ElSelect
} from "element-plus"
import { computed, reactive } from "vue"

type CompoundParams = {
  principal: number
  rate: number
  periodsPerYear: number
  years: number
  contribution: number
  contributionAtStart: boolean
}

function computeCompound({
  principal,
  rate,
  periodsPerYear,
  years,
  contribution,
  contributionAtStart
}: CompoundParams): number {
  // Here `rate` is the per-period nominal rate.
  const r = rate
  const n = periodsPerYear * years
  // Handle zero or near-zero rate to avoid division by zero and NaN
  if (Math.abs(r) < 1e-12) {
    return safeAdd(principal, safeMul(contribution, n))
  }
  const growth = pow1pr(r, n)
  let future = safeMul(principal, growth)
  if (contribution !== 0) {
    const factor = safeDiv(safeSub(growth, 1), r)
    const adj = contributionAtStart ? safeAdd(1, r) : 1
    future = safeAdd(future, safeMul(safeMul(contribution, adj), factor))
  }
  return roundTo(future)
}

const state = reactive({
  principal: 10000,
  ratePercent: 5,
  periodsPerYear: 1,
  years: 10,
  contribution: 0,
  timing: "end" as "start" | "end"
})

function getPerPeriodRate(): number {
  // 输入的利率单位与选择的频率一致：
  //  - 按年：输入为年利率 -> 每期利率 = 年利率
  //  - 按季度：输入为季利率 -> 每期利率 = 季利率
  //  - 按月：输入为月利率 -> 每期利率 = 月利率
  //  - 按日：输入为日利率 -> 每期利率 = 日利率
  return state.ratePercent / 100
}

const futureValue = computed(() =>
  computeCompound({
    principal: state.principal,
    rate: getPerPeriodRate(),
    periodsPerYear: state.periodsPerYear,
    years: state.years,
    contribution: state.contribution,
    contributionAtStart: state.timing === "start"
  })
)

const futureValueText = computed(() => futureValue.value.toFixed(2))

// Profit = final amount - principal - total contributions
const totalContributions = computed(
  () => state.contribution * state.periodsPerYear * state.years
)
const profit = computed(() =>
  roundTo(
    safeSub(
      safeSub(futureValue.value, state.principal),
      totalContributions.value
    )
  )
)
const profitText = computed(() => profit.value.toFixed(2))

// ---------- Precision helpers ----------
const DECIMAL_PLACES = 12
function roundTo(value: number, places = DECIMAL_PLACES): number {
  const factor = 10 ** places
  return Math.round((value + Number.EPSILON) * factor) / factor
}
function safeAdd(a: number, b: number): number {
  return roundTo(a + b)
}
function safeSub(a: number, b: number): number {
  return roundTo(a - b)
}
function safeMul(a: number | bigint, b: number | bigint): number {
  return roundTo(Number(a) * Number(b))
}
function safeDiv(a: number, b: number): number {
  return roundTo(a / b)
}
// Compute (1 + r)^n with rounding each step to mitigate FP drift
function pow1pr(rate: number, n: number): number {
  let base = roundTo(1 + rate)
  let res = 1
  let e = Math.floor(n)
  while (e > 0) {
    if (e & 1) res = safeMul(res, base)
    base = safeMul(base, base)
    e >>= 1
  }
  return res
}
</script>
